package com.mibao.defense;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Parcel;
import android.os.RemoteException;

public class DefenseService extends IDefense.Stub {

	static {
		System.loadLibrary("apk_parser");
	}

	public static native ArrayList<String> getApkLabels(String apkFile);

	private static DefenseService mInstance = null;
	private Context mContext;
	private IDefenseMonitor mMonitor;

	public static final int ACTION_GRANT = 0;
	public static final int ACTION_FORBID = 1;

	private static final String DESP_AM = "android.app.IActivityManager";
	private static final String DESP_PM = "android.content.pm.IPackageManager";
	private static final String DESP_CON = "android.net.IConnectivityManager";
	private static final String DESP_WIFI = "android.net.wifi.IWifiManager";
	private static final String DESP_BLU = "android.bluetooth.IBluetoothManager";
	private static final String DESP_DPM = "android.app.admin.IDevicePolicyManager";

	// TODO 1: Params checking
	// TODO 2: Changing mMonitor
	public static synchronized DefenseService getInstance(Context context,
			IDefenseMonitor monitor) {
		if (mInstance == null) {
			mInstance = new DefenseService(context, monitor);
		}
		return mInstance;
	}

	public DefenseService(Context context, IDefenseMonitor monitor) {
		mContext = context;
		mMonitor = monitor;
	}

	@Override
	public int checkAuthorization(Parcel data, Parcel reply)
			throws RemoteException {

		// 1 读取Parcel头
		data.setDataPosition(0); // 移动data指针到开始
		int formFlg = data.readInt(); // 从哪个服务传来 0:java 1: native
		int actionID = data.readInt(); // 操作id @see EventIndex
		int uid = data.readInt(); // 请求应用的uid
		int pid = data.readInt(); // pid

		// TODO 可选
		if (uid == mContext.getApplicationInfo().uid) {
			return ACTION_GRANT;
		}
		
		boolean allowed = true;
		if (actionID == ActionIndex.BLU_ENABLE) { // Bluetooth Opening
			LogUtil.d("Bluetooth Openning...");
			allowed = mMonitor.onBluetoothOpenning();

			reply.setDataPosition(0);
			if (allowed) {
				reply.writeInt(ACTION_GRANT);
				return ACTION_GRANT;
			} 
			else {
				reply.writeInt(ACTION_FORBID);
				return ACTION_FORBID;
			}
		} 
		else if (actionID == ActionIndex.BLU_DISABLE) { // Bluetooth Closing
			LogUtil.d("Bluetooth Closing...");
			allowed = mMonitor.onBluetoothClosing();

			reply.setDataPosition(0);
			if (allowed) {
				reply.writeInt(ACTION_GRANT);
				return ACTION_GRANT;
			} 
			else {
				reply.writeInt(ACTION_FORBID);
				return ACTION_FORBID;
			}
		} 
		else if (actionID == ActionIndex.WIFI_SET_WIFI_ENABLED) { // Wifi
																	// Openning/Closing
			data.enforceInterface(DESP_WIFI);

			int enable = data.readInt();
			if (enable == 1) {
				LogUtil.d("Wifi Openning...");
				allowed = mMonitor.onWifiOpenning();
			} 
			else if (enable == 0) {
				LogUtil.d("Wifi Closing...");
				allowed = mMonitor.onWifiClosing();
			}

			reply.setDataPosition(0);
			if (allowed) {
				reply.writeInt(ACTION_GRANT);
				return ACTION_GRANT;
			} 
			else {
				reply.writeInt(ACTION_FORBID);
				return ACTION_FORBID;
			}
		} 
		else if (actionID == ActionIndex.CON_SET_MOBILE_DATA_ENABLED) { // GPRS
																			// Openning/Closing
			data.enforceInterface(DESP_CON);

			int enable = data.readInt();
			if (enable == 1) {
				LogUtil.d("Mobile Data Openning...");
				allowed = mMonitor.onGprsOpenning();
			} 
			else if (enable == 0) {
				LogUtil.d("Mobile Data Closing...");
				allowed = mMonitor.onGprsClosing();
			}

			reply.setDataPosition(0);
			if (allowed) {
				reply.writeInt(ACTION_GRANT);
				return ACTION_GRANT;
			} 
			else {
				reply.writeInt(ACTION_FORBID);
				return ACTION_FORBID;
			}
		} 
		else if (actionID == ActionIndex.PM_PKG_DELETE) { // Package Deleting
			data.enforceInterface(DESP_PM);

			String packageName = data.readString();
			LogUtil.d("Package Deleting: " + packageName);

			allowed = mMonitor.onPackageDeleting(packageName);

			reply.setDataPosition(0);
			if (!allowed) {
				reply.writeInt(ACTION_FORBID);
				reply.writeInterfaceToken(DESP_PM);
				reply.writeString("xxx.xxx");
				reply.appendFrom(data, data.dataPosition(), data.dataAvail());
				reply.setDataPosition(0);
				return ACTION_FORBID;
			} 
			
			reply.writeInt(ACTION_GRANT);
			return ACTION_FORBID;
		} 
		else if (actionID == ActionIndex.PM_PKG_INSTALL) { // Package
																// Installing
			data.enforceInterface(DESP_PM);
			
			int hasUri = data.readInt();
			if (hasUri != 0) {
				Uri uri = Uri.CREATOR.createFromParcel(data);
	
				LogUtil.d("Package Installing, Uri: " + uri.toString() 
						+ "Uri.getPath: " + uri.getPath());
	
				// TODO Parse labels for this apk file
				String apkFile = uri.getPath();
				ArrayList<String> apkLabels = getApkLabels(apkFile);
				if (apkLabels != null) {
					for (String label : apkLabels) {
						LogUtil.d("label:" + label);
					}
	
					allowed = mMonitor.onPackageInstalling(apkLabels);
	
					if (allowed == false) {
						Uri fakeUri = Uri.parse("file:///xx.xx");
						
						reply.writeInt(ACTION_FORBID);
						reply.writeInterfaceToken(DESP_PM);
						reply.writeInt(1);
						fakeUri.writeToParcel(reply, 0);
						reply.appendFrom(data, data.dataPosition(), data.dataAvail());
						reply.setDataPosition(0);
						return ACTION_FORBID;
					}
				}
			}

			reply.setDataPosition(0);
			reply.writeInt(ACTION_GRANT);
			return ACTION_GRANT;
		} 
		else if (actionID == ActionIndex.DPM_SET_ACTIVE_ADMIN) {
			
			// 激活设备管理器不需要拦截，仅需底层放行
		} 
		else if (actionID == ActionIndex.DPM_REMOVE_ACTIVE_ADMIN) { 
			data.enforceInterface(DESP_DPM);

			int isNull = data.readInt();
			if (isNull == 0) {
				LogUtil.d("Policy Admin Removing, Policy Receiver is null, GRANT");
				reply.setDataPosition(0);
				reply.writeInt(ACTION_GRANT);
				return ACTION_GRANT;
			}

			ComponentName policyReceiver = ComponentName.CREATOR
					.createFromParcel(data);
			if (policyReceiver == null) {
				LogUtil.e("DefenseService, Policy Admin Removing, policyReceiver read from parcel is null, GRANT");
				reply.setDataPosition(0);
				reply.writeInt(ACTION_GRANT);
				return ACTION_GRANT;
			}

			allowed = mMonitor.onDevicePolicyRemoving(policyReceiver);
			if (allowed == false) {
				LogUtil.d("Device Policy Removing, policyReceiver:"
						+ policyReceiver.toString() + ", DENY");
				reply.setDataPosition(0);
				reply.writeInt(ACTION_FORBID);
				return ACTION_FORBID;
			}
			
			LogUtil.d("Device Policy Removing, policyReceiver:"
					+ policyReceiver.toString() + ", GRANT");
			reply.setDataPosition(0);
			reply.writeInt(ACTION_GRANT);
			return ACTION_GRANT;
		}
		else if (actionID == ActionIndex.PM_QUERY_INTENT_ACTIVITY) {
			LogUtil.d("[Java Binder] Calling queryIntentActivities from someone");
			data.enforceInterface(DESP_PM);
			Intent intent = null;
			
			if (0 != data.readInt()) {
				intent = android.content.Intent.CREATOR.createFromParcel(data);
			}
			
			if (null != intent) {
				String action  =  intent.getAction();
				Set<String> setCat = intent.getCategories();
				String targetPackName = intent.getPackage();
				
				if ((targetPackName != null && !targetPackName.isEmpty())
						&& !targetPackName.equals(mContext.getPackageName()) 
						&& action.equals(Intent.ACTION_MAIN) 
						&& setCat.contains(Intent.CATEGORY_LAUNCHER))
				{
					// 根据Uid获取调用者包名，用于隐藏图标功能中，判断调用者是否来自桌面应用
					PackageManager pm = mContext.getPackageManager();
					String packagesByUid[] = pm.getPackagesForUid(uid);
					if (packagesByUid == null) {
						return ACTION_GRANT;
					}
					String callerPackageName = packagesByUid[0];
					
					// 查询当前桌面类应用
					HashSet<String> homeList = new HashSet<String>();  
				    Intent intentHome = new Intent(Intent.ACTION_MAIN);  
				    intent.addCategory(Intent.CATEGORY_HOME);  
				    List<ResolveInfo> resolveInfo = pm.queryIntentActivities(intentHome,  
				            PackageManager.MATCH_DEFAULT_ONLY);  
				    for(ResolveInfo ri : resolveInfo){  
				    	homeList.add(ri.activityInfo.packageName);  
				    }
				    
					// 目的是只拦截桌面，不是桌面应用就都允许
					if (!homeList.isEmpty() && !homeList.contains(callerPackageName)) {
						return ACTION_GRANT;
					}
					
					LogUtil.d("[Java Binder] Calling queryIntentActivities from Launcher to PKG:" + targetPackName);
					
					allowed = mMonitor.onAppIconDisplaying(targetPackName);
					if (!allowed) {
						LogUtil.d("[Java Binder] ACTION_FORBID");
						reply.writeInt(ACTION_FORBID);
						java.util.List<ResolveInfo> _result = new ArrayList<ResolveInfo>();
						reply.writeNoException();
						reply.writeTypedList(_result);
						
						return ACTION_FORBID;
					}
					LogUtil.d("[Java Binder] ACTION_GRANT");
				}
			}
		}
		return ACTION_GRANT;
	}
}